#pragma once

#include <iostream>
#include <memory>
#include <string>
#include <string.h>
#include <cerrno>
#include <strings.h>


#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
#include "User.hpp"

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

namespace UdpServerArea
{
    using namespace ThreadPoolModule;
    using namespace UserArea;

    // 新增用户
    using adduser_t = std::function<void(InetAddr &id)>;

    // 移除用户
    using reuser_t = std::function<void(InetAddr &id)>;

    // 数据转发, 与UserManger中的Route绑定
    using route_t = std::function<void(int sockfd, const std::string &message)>;

    // 推送给线程池的任务
    using task_t = std::function<void()>;

    class UdpServer
    {
    public:
        UdpServer(int port = defaultport) : _sockfd(defaultsockfd), _addr(port), _isrunning(false)
        {
        }

        // 初始化服务器
        void InitServer()
        {
            // 创建socket
            _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
            if (_sockfd < 0)
            {
                // 将错误信息格入日志中
                LOG(LogLevel::FATALER) << "socket: " << strerror(errno);
                DIE(SOCKET_ERR);
            }
            LOG(LogLevel::INFO) << "socket success, socketfd is: " << _sockfd;

            // 填充网络信息, 并绑定
            // 将 socket 信息填充入结构体内
            // struct sockaddr_in local;

            // bzero(&local, sizeof(local)); // 将结构体内信息清空
            // local.sin_family = AF_INET;
            // local.sin_port = ::htons(_port);                  // 将主机字节顺序转为网络字节顺序   网络中的字节顺序为大端模式
            // local.sin_addr.s_addr = ::inet_addr(_ip.c_str()); // 使用系统调用将ip地址转为4字节形式的 char.char.char.char

            // 将套接字与当前主机 IP 地址和端口号绑定, 通常用 sockaddr_in 结构来指定
            int n = ::bind(_sockfd, _addr.NetAddr(), _addr.SockLen());
            if (n < 0)
            {
                LOG(LogLevel::FATALER) << "bind: " << strerror(errno);
                DIE(BIND_ERR);
            }

            LOG(LogLevel::INFO) << "bind success";
        }

        
        void RegisterService(adduser_t adduser,reuser_t reuser,route_t route)
        {
            _adduser = adduser;
            _remove_user = reuser;
            _route = route;
        }

        // 运行服务器
        void Start()
        {
            _isrunning = true;
            while (true)
            {
                // 输出消息内容 && 谁发给我的

                // peer 存储用户 sockaddr_in 的结构信息
                char inbuffer[1024];
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);

                // 服务器收取信息并作出反馈
                ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);
                if (n > 0)
                {
                    inbuffer[n] = 0;
                    std::string message;
                    InetAddr client(peer);

                    if (strcmp(inbuffer, "QUIT") == 0)
                    {
                        _remove_user(client);
                        message = client.Addr() + "# " + "我走了哈, 你们聊!";
                    }
                    else
                    {
                        _adduser(client);
                        message = client.Addr() + "# " + inbuffer;
                    }

                    task_t task = std::bind(UdpServer::_route, _sockfd, message);


                    ThreadPool<task_t>::GetInstance()->Equeue(task);


                    // std::string cliinfo = client.Ip() + ":" + std::to_string(client.Port()) + "# " + inbuffer;

                    // // 显示在服务器上的信息
                    // LOG(LogLevel::INFO) << cliinfo;

                    // // 回显到用户上的信息
                    // std::string echo_string = "echo# ";
                    // echo_string += cliinfo;
                    // ::sendto(_sockfd, echo_string.c_str(), sizeof(echo_string), 0, CONV(&peer), sizeof(peer));
                }
                _isrunning = false;
            }
        }

        ~UdpServer()
        {
            if (_sockfd != defaultsockfd)
                ::close(_sockfd);
        }

    private:
        int _sockfd; // 套接字描述符

        InetAddr _addr;

        // std::string _ip; // 服务器ip地址
        // uint16_t _port;  // 端口号
        bool _isrunning; // 是否正在运行

        adduser_t _adduser;
        reuser_t _remove_user;
        route_t _route;
    };
}
